home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 123_01.zip / DIO.C < prev    next >
Text File  |  1993-06-07  |  11KB  |  529 lines

  1. /* 
  2.     Directed I/O package for BDS C
  3.     Source:   dio.c
  4.     Version:  February 21, 1983
  5.  
  6.     This file was created from the BDS C v1.45 version of dio.c by:
  7.  
  8.         Edward K. Ream
  9.         1850 Summit Avenue
  10.         Madison, WI. 53705
  11.         (608) 231 - 2952
  12.  
  13.     See the file dio.doc for complete documentation.
  14.  
  15.     All changes to original code marked by:  ----- CHANGE -----
  16. */
  17.  
  18.  
  19. #include bdscio.h
  20. #include dio.h
  21.  
  22.  
  23. #define CON_INPUT    1   /* BDOS call to read console     */
  24. #define CON_OUTPUT    2   /* BDOS call to write to console */
  25. #define CON_STATUS    11  /* BDOS call to get status       */
  26.  
  27. #define CONTROL_C    3   /* Quit character             */
  28. #define STDERR        4   /* Standard Error descriptor     */
  29. #define INPIPE        2   /* bit setting to indicate directed
  30.                    input from a temp. pipe file  */
  31. #define VERBOSE        2   /* bit setting to indicate output
  32.                    is to go to the console AND to
  33.                       the directed output */
  34.  
  35. /* ----- CHANGE ----- a new definition */
  36. #define LST_OUT    5                /* BDOS list output */
  37.  
  38.  
  39.  
  40. /* Redirect the STD_IN, STD_OUT, and STD_ERR streams. */
  41.  
  42. #define argc *argcp
  43.  
  44. dioinit(argcp, argv)
  45. int *argcp;
  46. char **argv;
  47. {
  48.     int i,j, argcount;
  49.  
  50.     /* No directed I/O by default. */
  51.     /* ----- CHANGE ----- some new variables added */
  52.     _diflag = _doflag = _deflag = _pipef = FALSE;
  53.     _dispec = _dospec = _despec = ERROR;
  54.     _nullpos = &argv [argc];
  55.  
  56. #ifdef BUF_CONS
  57.     _conbuf[0] = 0;            /* no characters in buffer yet    */
  58.     _conbufp = _conbuf;        /* point to null buffer     */
  59. #endif
  60.  
  61.     argcount = 1;
  62.  
  63.     /* Scan the command line for < and >  and |  */
  64.     for (i = 1; i < argc; i++) {
  65.  
  66.         /* Stop if the last thing we saw was a pipe. */
  67.         if (_pipef) {
  68.             break;
  69.         }
  70.  
  71.         switch (*argv [i]) {
  72.  
  73.  
  74. case '<':    /* Directed input. */
  75.  
  76.         if (!argv [i] [1]) {
  77.             /* ----- CHANGE ----- avoid goto */
  78.             fprintf(STD_ERR,
  79.                 "bad '<' redirection\n");
  80.             exit();
  81.         }
  82.  
  83.         else if (fopen(&argv[i][1], _dibuf) == ERROR) {
  84.             fprintf(STD_ERR,"Can't open %s\n",
  85.                 &argv [i] [1]);
  86.             exit();
  87.         }
  88.  
  89.         _diflag = TRUE;
  90.         if (strcmp(argv[i],"<TEMPIN.$$$") == 0) {
  91.              _diflag |= INPIPE;
  92.         }
  93.  
  94.         goto movargv;
  95.  
  96. /* Pipes:
  97.  *    The vertical bar (|) separates programs and arguments.
  98.  *    For the CURRENT program, only arguments up to the bar
  99.  *    are visible.  The remaining arguments are passed to
  100.  *    the following program in the pipe by calling execv().
  101.  *
  102.  *    _pipedist points to argument following the bar.
  103.  *    It must be name of a program.
  104.  *    _savei points to the LIST of arguments which will
  105.  *    be passed to execv() by dioflush().
  106.  */
  107.  
  108. case '|':    /* pipe */
  109.  
  110.         if (!argv [i] [1]) {
  111.             /* ----- CHANGE ----- avoid goto */
  112.             fprintf(STD_ERR,
  113.                 "bad pipe specifier\n");
  114.             exit();
  115.         }
  116.  
  117.         /* We are now in pipe mode. */
  118.         _pipef++;
  119.  
  120.         /* Point to the FOLLOWING program's name. */
  121.         _pipedest = &argv [i] [1];
  122.  
  123.         if (argv [i] [1]) {
  124.             /* Convert the bar to a file name. */
  125.             argv [i] = ">TEMPOUT.$$$";
  126.  
  127.             /* Point to the FOLLOWING program's
  128.              * argument list.
  129.              */
  130.             _savei = &argv [i];
  131.         }
  132.  
  133.         goto out;
  134.  
  135. /* ----- CHANGE -----    this whole case is new.
  136.  *            If you use this you must make a
  137.  *            slight modification to putc().
  138.  *            The new putc is also on this file.
  139.  */
  140.  
  141. case '@':    /* Directed error output */
  142.         /* Requires a slight mod to  putc() */
  143.  
  144.         if (!argv [i] [1]) {
  145.             fprintf(STD_ERR,
  146.                 "bad '@' redirection\n");
  147.             exit();
  148.         }
  149.  
  150.         if (strcmp (&argv [i] [1], PRINTER) == 0){
  151.             _despec = DEV_LST;
  152.         }
  153.         if (_despec != ERROR) {
  154.             _deflag++;
  155.             goto movargv;
  156.         }
  157.  
  158.         unlink (&argv [i] [1]);
  159.         if (fcreat (&argv [i] [1], _debuf) == ERROR) {
  160.             fprintf(STD_ERR, "Can't creat %s\n",
  161.                 &argv [i] [1]);
  162.             exit();
  163.         }
  164.         _deflag++;
  165.         goto movargv;
  166.         
  167.  
  168. case '+':       /* Verbose output to console and file. */
  169.  
  170.         _doflag |= VERBOSE;
  171.             
  172. /* ----- CHANGE ----- this label used to be foo. */
  173.         
  174. out: case '>':    /* Directed output */
  175.     
  176.         if (!argv [i] [1])  {
  177.             /* ----- CHANGE ----- */
  178.             fprintf(STD_ERR,
  179.                 "Bad '>' redirection\n");
  180.             exit();
  181.         }
  182.  
  183.         /* ----- CHANGE ----- look for special files */
  184.         if (strcmp (&argv [i] [1], PRINTER) == 0){
  185.             _dospec = DEV_LST;
  186.         }
  187.         if (_dospec != ERROR) {
  188.             _doflag++;
  189.             goto movargv;
  190.         }
  191.  
  192.         unlink(&argv [i] [1]);
  193.         if (fcreat(&argv [i] [1], _dobuf) == ERROR) {
  194.                fprintf(STD_ERR,"Can't create %s\n",
  195.                 &argv[i][1]);
  196.                exit();
  197.         }
  198.         _doflag++;
  199.  
  200.         /* Common redirected I/O processing:
  201.          *
  202.          */
  203.  
  204. movargv:    if (!_pipef) {
  205.  
  206.             /* Delete the redirected argument. */
  207.             for (j = i; j < argc; j++) {
  208.                 argv[j] = argv[j+1];
  209.             }
  210.             (argc)--;
  211.             i--;
  212.             _nullpos--;
  213.         }
  214.         else {
  215.             /* Make args after the bar invisible
  216.              * until the next program starts.
  217.              */
  218.             argc = argcount;
  219.             argv [argc] = 0;
  220.         }
  221.         break;
  222.  
  223. default:    /* normal argument */
  224.         argcount++;
  225.  
  226.         }
  227.     }
  228. }
  229.  
  230. #undef argc
  231.  
  232.  
  233. /* Close all files and chain to the next program.
  234.  * Abort any open pipe if errcode is not zero.
  235.  */
  236.  
  237. dioflush()
  238. {
  239.     /* Close the standard input stream. */
  240.     if (_diflag && _dispec == ERROR) {
  241.         fclose(_dibuf);
  242.         if (_diflag & INPIPE) {
  243.             unlink("tempin.$$$");
  244.         }
  245.     }
  246.  
  247.     /* Close the standard output stream. */
  248.     if (_doflag && _dospec == ERROR) {
  249.         putc(CPMEOF,_dobuf);
  250.         fflush(_dobuf);
  251.         fclose(_dobuf);
  252.  
  253.         /* in case previous pipe was aborted */
  254.         unlink("tempin.$$$");
  255.         rename("tempout.$$$","tempin.$$$");
  256.     }
  257.  
  258.     /* Close the error output stream. */
  259.     /* ----- CHANGE ----- this is new code */
  260.     if (_deflag && _despec == ERROR) {
  261.  
  262.         putc(CPMEOF, _debuf);
  263.         fflush(_debuf);
  264.         fclose(_debuf);
  265.         }
  266.  
  267.     /* Start executing the NEXT program in the pipe
  268.      * by calling execv (_pipedest, _savei).
  269.      * As you will recall, _pipedest and _savei are
  270.      * set up by initst().
  271.      */
  272.     /* ----- CHANGE ----- this test is different */
  273.     if (_doflag && _pipef)  {
  274.  
  275.         /* The first arg will redirect the input. */
  276.         *_savei = "<TEMPIN.$$$";
  277.  
  278.         /* Wipe out the zero'th argument. */
  279.         *_nullpos = NULL;
  280.  
  281.         /* Fire up the next program.
  282.          * The arguments to execv are:
  283.          *    1.  The name of the program to execute.
  284.          *    2.  A pointer to the arg list.
  285.          */
  286.         
  287.         if (execv(_pipedest,_savei) == ERROR) {
  288.             fprintf(STD_ERR, "\7Broken pipe\n");
  289.             exit();
  290.         }
  291.     }
  292. }
  293.  
  294.  
  295. /*
  296.     This version of "getchar" replaces the regular version when using
  297.     directed I/O. Note that the "BUF_CONS" defined symbol (in DIO.H)
  298.     controls whether the console input is to be raw or buffered (see
  299.     NOTES section of dio.doc)
  300. */
  301.  
  302. getchar()
  303. {
  304.     int c;
  305.  
  306.     /* ----- CHANGE ----- consider _dispec as well */
  307.     if (_diflag && _dispec == ERROR) {
  308.         if ((c = getc(_dibuf)) == '\r') c = getc(_dibuf);
  309.     }
  310.     else
  311.  
  312. #ifdef BUF_CONS        /* For buffered console input, get a line of text   */
  313.     {        /* from the BDOS (using "gets"), & insert newline:  */
  314.         if (!*_conbufp) {   
  315.             gets(_conbufp = _conbuf);
  316.             _conbuf[strlen(_conbuf) + 1] = '\0';
  317.             _conbuf[strlen(_conbuf)] = '\n';
  318.         }
  319.         c = *_conbufp++;
  320.     }
  321. #else            /* for raw console input, simulate normal "getchar": */
  322.         if ((c = bdos(CON_INPUT)) == CONTROL_C) exit();
  323. #endif
  324.  
  325.     if (c == CPMEOF) return EOF;         /* Control-Z is EOF key     */
  326.  
  327.     if (c == '\r') 
  328.     {
  329.         c = '\n';
  330. #ifndef BUF_CONS
  331.         if (!_diflag) bdos(2,'\n');  /* echo LF after CR to console */
  332. #endif
  333.     }
  334.     return c;
  335. }
  336.  
  337.  
  338.  
  339. /*
  340.     This version of "putchar" replaces the regular version when using
  341.     directed I/O:
  342. */
  343.  
  344. putchar(c)
  345. char c;
  346. {
  347.     char *static;
  348.     static = "";    /* remembers last character sent; start out null */
  349.  
  350.     /* ----- CHANGE ----- wait on ^S, abort pipe on ^C. */
  351.     chkkey();
  352.  
  353.     /* ----- CHANGE ----- consider _dospec as well */
  354.     if (_doflag && _dospec == ERROR)
  355.     {
  356.         if (c == '\n' && *static != '\r') putc('\r',_dobuf);
  357.         *static = c;
  358.         if(putc(c,_dobuf) == ERROR)
  359.         {
  360.             fprintf(STDERR,"File output error; disk full?\n");
  361.             exit();
  362.         }
  363.  
  364.         /* ----- CHANGE ----- BUG FIX return c */
  365.         if (!(_doflag & VERBOSE)) return c;
  366.     }
  367.  
  368.     /* ----- CHANGE ----- this whole section is new */
  369.     if (_doflag && _dospec == DEV_LST) {
  370.  
  371.         /* Send character to the list device. */
  372.         if (c == '\n' && *static != '\r') {
  373.             /* comment out -----
  374.             bdos (LST_OUT, '\r');
  375.             ----- end comment out */
  376.             putc('\r', DEV_LST);
  377.         }
  378.         *static = c;
  379.         /* comment out -----
  380.         bdos (LST_OUT, c);
  381.         ----- end comment out */
  382.         putc(c, DEV_LST);
  383.         return c;
  384.     }
  385.  
  386.     if (c == '\n' && *static != '\r') bdos(CON_OUTPUT,'\r');
  387.     bdos(CON_OUTPUT,c);
  388.     *static = c;
  389.  
  390.     /* ----- CHANGE ----- return c! */
  391.     return c;
  392. }
  393.  
  394.  
  395. /* A new version of putc() for use with directed I/O to special files. */
  396.  
  397. /* comment out -----
  398. #define ACKNAK 1
  399. ----- end comment out */
  400.  
  401. #define DAV 1        /* data available bit for printer    */
  402. #define SIIA  0x14    /* data port for printer        */
  403. #define SIIAC 0x16    /* control port for printer        */
  404.  
  405. int putc(c,iobuf)
  406. char c;
  407. FILE *iobuf;
  408. {
  409.     /* ----- CHANGE ----- wait on ^S, abort pipe on ^C. */
  410.  
  411.     /* ----- CHANGE ----- this number used to be 4 */
  412.  
  413.     if (iobuf <= 5)            /* handle special device codes: */
  414.      {
  415.         switch (iobuf)
  416.          {
  417.             case STD_OUT:    return putchar(c);  /* std output */
  418.             case DEV_LST:    
  419. #ifdef ACKNAK
  420.                     /* output the character */
  421.                     bdos(5,c);
  422.                     if (c != '\n') {    
  423.                         return c;
  424.                     }
  425.                     /* output ACK */
  426.                     bdos(5,3);
  427.                     /* wait for status */
  428.                     while ( (inp(SIIAC) & DAV) == 0) {
  429.                         ;
  430.                     }
  431.                     /* wait for NAK */
  432.                     while ( (inp(SIIA) & 0x7f) != 6) {
  433.                         ;
  434.                     }
  435.                     return c;
  436. #else
  437.                     return (bdos(5,c)); /* list dev.  */
  438. #endif
  439.  
  440.             case DEV_PUN:    return (bdos(4,c)); /* to punch   */
  441.  
  442.             /* ----- CHANGE ----- do more here */
  443.             case STD_ERR:    return _puterr(c);
  444.  
  445.             /* ----- CHANGE ----- add DEV_TTY  */
  446.             case DEV_TTY:
  447.                      if (c == '\n') {
  448.                         bdos(2,'\r');
  449.                     }
  450.                     return bdos(2,c);
  451.          }    
  452.      }
  453.     if (!iobuf -> _nleft--)        /*   if buffer full, flush it     */
  454.      {
  455.         if ((write(iobuf -> _fd, iobuf -> _buff, NSECTS)) != NSECTS)
  456.             return ERROR;
  457.         iobuf -> _nleft = (NSECTS * SECSIZ - 1);
  458.         iobuf -> _nextp = iobuf -> _buff;
  459.      }
  460.     return *iobuf -> _nextp++ = c;
  461. }
  462.  
  463.  
  464. /* ----- CHANGE ----- this whole routine is new. */
  465. /* Utility routine for putc. */
  466.  
  467. _puterr(c)
  468. char c;
  469. {
  470.     if (_deflag && _despec == ERROR) {
  471.         /* direct error output to a file. */
  472.         return putc(c, _debuf);
  473.     }
  474.     else if (_deflag && _despec == DEV_LST) {
  475.         return putc(c, DEV_LST);
  476.     }
  477.     else {
  478.         /* Direct error output to the console. */
  479.         return putc(c, DEV_TTY);
  480.     }
  481. }
  482.  
  483.  
  484. /* ----- CHANGE ----- this whole routine is new */
  485. /*
  486.     Look for an interrupt from the keyboard.
  487.     Suspend processing on ^S until another key hit.
  488.     Abort program and any open pipe on ^C.
  489.     This program uses calls to BIOS to avoid BDOS weirdnesses.
  490. */
  491.  
  492. chkkey()
  493. {
  494.     int c;
  495.  
  496.     /* Character ready ? */
  497.     if (bios(2,0) == 0) {
  498.         return;
  499.     }
  500.     /* Read the character.  Do NOT echo. */
  501.     c = bios(3,0) & 0x7f;
  502.  
  503.     /* Abort pipe on control-C. */
  504.     if (c == 3) {
  505.         dioflush();
  506.         exit();
  507.     }
  508.  
  509.     /* Control S.  Wait for any character. */
  510.     else if (c == 19) {
  511.         while (bios(2,0) == 0) {
  512.             ;
  513.         }
  514.         /* Read the character to clear status. */
  515.         bios(3,0);
  516.         return;
  517.     }
  518.  
  519.     /* All other characters. */
  520.     return;
  521. }
  522. ;
  523.         }
  524.         /* Read the character to clear status. */
  525.         bios(3,0);
  526.         return;
  527.     }
  528.  
  529.     /* All other characters. *